package service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import service.PointService;
import bean.Distance;
import bean.Intersection;
import bean.Point;
import bean.Road;

import common.BeanUtils;

import dao.IntersectionDao;
import dao.PointDao;
import dao.RoadDao;
import exception.DBException;

public class PointServiceImpl implements PointService {

	private PointDao pointDao;
	private RoadDao roadDao;
	private IntersectionDao intersectionDao;

	@Override
	public List<Road> saveOrUpdate(List<Road> roads) throws DBException {

		removeSame(roads);

		for (Road r : roads) {

			for (int i = 0; i < r.getPoint().length; i++) {

				Point p = r.getPoint()[i];

				Point ps = pointDao.queryByModel(p);

				if(ps!=null)
					r.getPoint()[i] = ps;

			}

		}

		for (Road r : roads) {
			if (r.getId() == 0)
				for (Point p : r.getPoint()) {
					List<Road> rs = new ArrayList<Road>();
					if (p.getRoad() == null) {
						rs.add(r);
					} else {
						rs.addAll(Arrays.asList(p.getRoad()));
						rs.add(r);
					}
					p.setRoad(rs.toArray(new Road[rs.size()]));
				}
		}

		for (Road road : roads) {
			pointDao.update(road.getPoints());
		}

		return roads;
	}

	private void removeSame(Collection<Road> c) {

		for (Road r1 : c) {

			for (Road r2 : c) {

				if (r1 == r2)
					continue;

				for (int i = 0; i < r1.getPoint().length; i++)

					for (int j = 0; j < r2.getPoint().length; j++) {

						Point p1 = r1.getPoint()[i];

						Point p2 = r2.getPoint()[j];

						if (p1.equals(p2)) {

							r1.getPoint()[i] = r2.getPoint()[j];

						}

					}

			}

		}

		for (Road r : c) {

			r.setPoint(r.getPoint());

		}

	}

	public PointDao getPointDao() {
		return pointDao;
	}

	public void setPointDao(PointDao pointDao) {
		this.pointDao = pointDao;
	}

	public RoadDao getRoadDao() {
		return roadDao;
	}

	public void setRoadDao(RoadDao roadDao) {
		this.roadDao = roadDao;
	}

	@Override
	public int[] shortestPoint(Point[] points, int area) throws DBException {
		List<Distance> dis = roadDao.selectDistances(area);
		int[] ids = new int[points.length];
		Distance t1 = BeanUtils.inRoad(dis, points[0]);
		Distance t2 = BeanUtils.inRoad(dis, points[1]);
		if (t1 != null && t2 != null) {
			// 两个点在同一条路上,并且（道路方向）与（起点到终点连线方向）一致
			if (t1.getId() == t2.getId()
					&& BeanUtils.hypot(t1.getPoint1(), points[0]) <= BeanUtils
							.hypot(t1.getPoint1(), points[1])) {
				ids[0] = -1;
				ids[1] = -1;
			} else {
				ids[0] = t1.getPoint2().getId();
				ids[1] = t2.getPoint1().getId();
			}
		} else if (t1 == null && t2 != null) {
			ids[1] = t2.getPoint1().getId();
			Set<Point> ps = new HashSet<Point>();
			for (Distance distance : dis) {
				ps.add(distance.getPoint1());
				ps.add(distance.getPoint2());
			}
			Point p1 = points[0];
			float min = 0f;
			for (Point p2 : ps) {
				float t = BeanUtils.hypot(p1, p2);
				if (t < min || min == 0f) {
					min = t;
					ids[0] = p2.getId();
				}
			}

		} else if (t2 == null && t1 != null) {
			ids[0] = t1.getPoint2().getId();
			Set<Point> ps = new HashSet<Point>();
			for (Distance distance : dis) {
				ps.add(distance.getPoint1());
				ps.add(distance.getPoint2());
			}
			Point p1 = points[1];
			float min = 0f;
			for (Point p2 : ps) {
				float t = BeanUtils.hypot(p1, p2);
				if (t < min || min == 0f) {
					min = t;
					ids[1] = p2.getId();
				}
			}
		}
		// 若找不到满意的点，查找距起点终点最近的关键点当作寻路起点终点
		if (ids[0] == 0 && ids[1] == 0) {
			Set<Point> ps = new HashSet<Point>();
			for (Distance distance : dis) {
				ps.add(distance.getPoint1());
				ps.add(distance.getPoint2());
			}
			for (int i = 0; i < 2; i++) {
				Point p1 = points[i];
				float min = 0f;
				for (Point p2 : ps) {
					float t = BeanUtils.hypot(p1, p2);
					if (t < min || min == 0f) {
						min = t;
						ids[i] = p2.getId();
					}
				}
			}
		}

		return ids;
	}

	@Override
	public List<Point> findPointsByIds(int[] ids) throws DBException {
		List<Point> points = new ArrayList<Point>(ids.length);
		for (int i = 0; i < ids.length; i++) {
			points.add(pointDao.query(ids[i]));
		}
		return points;
	}

	@Override
	public boolean saveLightsPoints(List<Intersection> lights)
			throws DBException {
		for (Intersection l : lights) {
			l.setE1(l.getE1().getX() == -1 ? null : pointDao.queryByModel(l
					.getE1()));
			l.setE2(l.getE2().getX() == -1 ? null : pointDao.queryByModel(l
					.getE2()));
			l.setN1(l.getN1().getX() == -1 ? null : pointDao.queryByModel(l
					.getN1()));
			l.setN2(l.getN2().getX() == -1 ? null : pointDao.queryByModel(l
					.getN2()));
			l.setS1(l.getS1().getX() == -1 ? null : pointDao.queryByModel(l
					.getS1()));
			l.setS2(l.getS2().getX() == -1 ? null : pointDao.queryByModel(l
					.getS2()));
			l.setW1(l.getW1().getX() == -1 ? null : pointDao.queryByModel(l
					.getW1()));
			l.setW2(l.getW2().getX() == -1 ? null : pointDao.queryByModel(l
					.getW2()));
		}
		return intersectionDao.save(lights);
	}

	public IntersectionDao getIntersectionDao() {
		return intersectionDao;
	}

	public void setIntersectionDao(IntersectionDao intersectionDao) {
		this.intersectionDao = intersectionDao;
	}

}
